﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Meow.Core.Log;
using Silk.NET.OpenGL;

namespace Meow.Core.Render
{
    public interface IVertexBuffer : IDisposable
	{
		void Bind();
	}

	public interface IVertexBuffer<T> : IVertexBuffer
		where T : struct
	{
		void SetVertexData(T[] data, int length,
	uint[] indices, int indicesLength);
	}

	sealed class VertexBuffer<T> : IDisposable, IVertexBuffer<T>
			where T : struct
	{
		static readonly int VertexSize = Marshal.SizeOf(typeof(T));
		GL GLcontext;
		uint _vbo;
		uint _ebo;

		bool disposed = false;

		public VertexBuffer(GL gl)
		{
			GLcontext = gl;

			_vbo = GLcontext.GenBuffer();
			GLcontext.BindBuffer(BufferTargetARB.ArrayBuffer, _vbo);
			DebugUtil.CheckGLError(GLcontext);

			_ebo = GLcontext.GenBuffer();
			GLcontext.BindBuffer(BufferTargetARB.ElementArrayBuffer, _ebo);
			DebugUtil.CheckGLError(GLcontext);
		}

		public unsafe void SetVertexData(T[] data, int length,
	uint[] indices, int indicesLength)
		{
			Bind();

			fixed (void* v = Exts.StructArrayToBytes(data))
				GLcontext.BufferData(BufferTargetARB.ArrayBuffer, (nuint)(length * VertexSize), v, BufferUsageARB.StaticDraw); //Setting buffer data.
			DebugUtil.CheckGLError(GLcontext);

			fixed (uint* buf = indices)
				GLcontext.BufferData(BufferTargetARB.ElementArrayBuffer, (nuint)(indicesLength * sizeof(uint)), buf, BufferUsageARB.StaticDraw);
			DebugUtil.CheckGLError(GLcontext);
		}

		public void Bind()
		{
			GLcontext.BindBuffer(BufferTargetARB.ArrayBuffer, _vbo);
			DebugUtil.CheckGLError(GLcontext);
			GLcontext.BindBuffer(BufferTargetARB.ElementArrayBuffer, _ebo);
			DebugUtil.CheckGLError(GLcontext);
		}

		public void Dispose()
		{
			if (disposed)
				return;
			disposed = true;
			GLcontext.DeleteBuffer(_vbo);
			DebugUtil.CheckGLError(GLcontext);

			GLcontext.DeleteBuffer(_ebo);
			DebugUtil.CheckGLError(GLcontext);

		}
	}
}
